'''
Created on Apr 12, 2011

@author: posttool
'''
import logging
from google.appengine.ext import db
from impact import platform

class WidgetCategory(platform.ImpactModel):
	'''
	Widget
	'''
	name = db.StringProperty()
	widgets = db.ListProperty(db.Key, default=None)
	categories = db.ListProperty(db.Key, default=None)

	def delete(self):
		for w in self.widgets:
			db.get(w).delete()
		for c in self.categories:
			db.get(c).delete()
		platform.ImpactModel.delete(self)

WIDGETS_MODULE		 	= None
WIDGET_CLASS_CACHE 		= {}
ROOT = None
REGISTRY = None
class WidgetRegistry(platform.ImpactModel):
	'''
	Each WidgetRegistry entity represents a pointer to a WidgetDefinition.
	Its key_name is the class name of the WidgetDefinition.
	The WidgetRegister requires that another class set its WIDGET_MODULE
	so that the class can make instances of the WidgetDefinition by
	the following convention <code>getattr(WIDGETS_MODULE, self.key().name())</code>
	'''
	#key_name maps to widget class_name, see definition_class
	name 			= db.StringProperty()
	description 	= db.TextProperty()
	icon 			= db.BlobProperty()
	is_correlation 	= db.BooleanProperty()
	is_live_data_widget = db.BooleanProperty()
	#these are no currently stored in the database
	#they can be copied from the def class with add_props
	required_connection_descriptors	= platform.PickleProperty()
	service_selector_names	 		= db.StringListProperty()
	service_selector_types	 		= db.StringListProperty()



	'''
	Ultimately, everything might go in the database.
	Especially if we have a widget submission process that is open.
	'''
	#author = db.UserProperty()
	#python_code = db.TextProperty()
	#js_code = db.TextProperty()
	#html_markup = db.TextProperty()
	#rating
	#number_of_installs

	@property
	def categories(self):
		return WidgetCategory.gql("WHERE widgets = :1", self.key())

	@property
	def category(self):
		return WidgetCategory.gql("WHERE widgets = :1", self.key())[0]

	@property
	def definition(self):
		if WIDGETS_MODULE is None:
			raise platform.ImpactException('WidgetRegistry requires WIDGETS_MODULE')

		global WIDGET_CLASS_CACHE
		#this is the way we deal with definitions for now once
		#we have uploaded stuff we would create an instance of
		#widget definition and fill out its methods based on type js,python,xml etc
		class_name = self.key().name()

		clz = WIDGET_CLASS_CACHE.get(class_name)
		if clz is not None:
			return clz;
		clz = getattr(WIDGETS_MODULE, self.key().name())
		WIDGET_CLASS_CACHE[class_name] = clz
		return clz

	def has_definition(self):
		if WIDGETS_MODULE is None:
			raise platform.ImpactException('WidgetRegistry requires WIDGETS_MODULE')
		return hasattr(WIDGETS_MODULE, self.key().name())

	#NOTE: as of now nothing that isnt in the db model makes it back to the client
	#since we use IMpactModel.to_dict to send this stuff back
	#that method ignores properties not in the db bean.

	def add_config_props(self):
		if not self.has_definition():
			return
		self.required_connection_descriptors  = self.definition()._get_connections()
		self.service_selector_names 		  = self.definition()._get_service_selector_names()
		self.service_selector_types 		  = self.definition()._get_service_selector_types()
		self.is_correlation                   = self.definition()._is_correlation()
		self.is_live_data_widget              = self.definition()._is_live_data_widget()


class WidgetDefinition():

	CONNECTION_TYPE_FACEBOOK 		  = "Facebook"
	CONNECTION_TYPE_TWITTER  		  = "Twitter"
	CONNECTION_TYPE_YOUTUBE  		  = "YouTube"
	CONNECTION_TYPE_GOOGLE_ANALYTICS  = "GoogleAnalytics"
	CONNECTION_TYPE_VIMEO			  = "Vimeo"
	CONNECTION_TYPE_TEST			  = "Test"

	PROPS_EDITOR_ROOT        = "templates/forms/widget-props-editors"
	PROPS_EDITOR_TYPE_CORRELATION  = 'correlation'
	PROPS_EDITOR_TYPE_BASIC  = 'basic'
	PROPS_EDITOR_TYPE_TEXT   = 'text'
	PROPS_EDITOR_TYPE_EMBED  = 'embed'
	PROPS_EDITOR_TYPE_CUSTOM  = 'custom';

	SELECTOR_TYPE_SELECT  = 'select';
	SELECTOR_TYPE_FREE_TEXT  = 'input';

	def get_name(self):
		return self.__class__.__name__

	def is_correlation(self):
		return False

	def is_live_data_widget(self):
		return False

	def get_connections(self):
		return []

	def get_service_selector_names(self):
		return []

	def get_service_selector_types(self):
		return []

	def get_data(self,api,selector_values,props):
		pass

	def get_selector_data(self,api,name,selector_values):
		return [],[]

	def get_props_editor(self):
		return WidgetDefinition.PROPS_EDITOR_TYPE_BASIC

	def get_default_props(self):
		return {'display-style':'total'}

	#-----system calls----------------#
	def _get_connections(self):
		cc = self.get_connections()
		#convenience so we can declare widget connection types as a single string
		#cc = [{'type':c,'name':c,'scopes':[]} for c in cc if not isinstance(c,dict)]
		for i in range(len(cc)):
			if not isinstance(cc[i],dict):
				cc[i] = {'type':cc[i],'name':cc[i],'scopes':cc[i]}
		return cc

	def _get_scopes(self):
		ss = self.get_scopes()
		return ss

	def _get_service_selector_names(self):
		sn = self.get_service_selector_names()
		return sn

	def _get_service_selector_types(self):
		st = self.get_service_selector_types()
		return st
	
	def _get_apis(self,wi_or_proxy):
		cc = self._get_connections()
		nc = len(cc)
		api = None

		if nc == 1:
			if hasattr(wi_or_proxy,'props'):
				api = wi_or_proxy.connections[cc[0]['name']].get_api()
			else:
				api = wi_or_proxy.connection.get_api() #this is the proxy
		else:
			api = {}
			for c in cc:
				api[c] = wi_or_proxy.connections[c['name']].get_api()
		return api

	def _get_data(self,connection,selector_values,props):
		if connection != None:
			api = connection.get_api()#self._get_apis(wi_or_proxy)
		else:
			api = {}
		return self.get_data(api,selector_values,props)

	def _get_selector_data(self,wi,name):
		api = self._get_apis(wi)
		selector_display_values, selector_values  = self.get_selector_data(api, name,wi.selector_values)
		if not selector_values:
			selector_values = selector_display_values
		return selector_display_values,selector_values

	def _get_default_props(self):
		return self.get_default_props()

	def _get_props_editor(self):
		return self.get_props_editor()

	def _get_props_editor_template(self):
		return WidgetDefinition.PROPS_EDITOR_ROOT+'/'+self._get_props_editor()+".html"

	def _is_correlation(self):
		return self.is_correlation()

	def _is_live_data_widget(self):
		return self.is_live_data_widget()

##################################################################################################
######################################  INSTALL WIDGETS  #########################################
##################################################################################################

config     = None
def init(app_config):
	global config
	config		= app_config['widget']
	if config['bootstrap']:
		install_widgets(True)
	init_root_and_registry()

def install_widgets(force=True):

	root = WidgetCategory.get_by_key_name('root')
	if force:
		if root is not None:
			logging.info('deleting old widget root')
			root.delete()

	categories = []

	categories.append( add_widget('facebook', {
			 'name': 	'Facebook',
			 'widgets': [
						['facebook_get_friends', 'Get Friends'],
						['facebook_get_my_posts', 'Get My Posts'],
						['facebook_get_comments', 'Get Comments'],
						['facebook_get_page_views', 'Get Page views/day'],
						['facebook_get_fan_posts', 'Get Fan Posts'],
						['facebook_get_page_likes', 'Get Page Likes'],
						['facebook_get_video_likes', 'Get Video Likes'],
						['facebook_get_album_likes', 'Get Album Likes'],
						
					]}).key() )

	categories.append( add_widget('twitter', {
		 'name': 	'Twitter',
		 'widgets': [
						['twitter_get_followers', 'Get followers'],
						['twitter_get_tweets', 'Get tweets'],
						['twitter_get_mentions', 'Get mentions'],
						['twitter_get_retweets', 'Get your retweets'],
						['twitter_get_hashtag_search', 'Get your hashtag/search'],
					]}).key() )

	categories.append( add_widget('google_analytics', {
		 'name': 	'Google Analytics',
		 'widgets': [
						['google_analytics_get_page_views', 'Get page views'],
						['google_analytics_get_site_visit', 'Get Site Visits'],
						['google_analytics_get_page_per_visit', 'Get Page Per Visit'],
						['google_analytics_get_bounce_rate', 'Get Bounce Rate'],
						['google_analytics_get_referrers', 'Site Referrers'],
						['google_analytics_get_absolute_unique_visitors', 'Absolute Unique Visitors'],
						['google_analytics_get_percent_new_visits', '% New Visits'],
						['google_analytics_get_browsers', 'Browsers (Visitors)'],
						['google_analytics_get_connection_speed', 'Connection Speed (Visitors)'],
						['google_analytics_get_avg_time_on_site', 'Avg. Time on Site'],
					]}).key() )

	categories.append( add_widget('you_tube', {
		 'name': 	'You Tube',
		 'widgets': [
						['you_tube_get_views', 'Get views'],
						['you_tube_get_channel_views', 'Get Channel views'],
						['you_tube_get_channel_subscribers', 'Get Channel Subscribers']
					]}).key() )

	categories.append( add_widget('vimeo', {
		 'name': 	'Vimeo',
		 'widgets': [
						['vimeo_get_views', 'Get views'],
						['vimeo_get_channel_views', 'Get channel views']
					]}).key() )

	categories.append( add_widget('custom', {
		 'name': 	'Custom',
		 'widgets': [
						['custom_text', 'Text'],
						['custom_embed', 'Embed'],
						['custom_manual_or_xml', 'Manual or XML'],
						['get_google_search_web', 'Google Web Search'],
						['get_google_search_blog', 'Google blog Search'],
						['get_google_search_news', 'Google news Search']
					]}).key() )

	categories.append( add_widget('correlation', {
		 'name': 	'Correlation',
		 'widgets': [
						['impact_correlation', 'Correlate Widgets']
					]}).key() )

	root = WidgetCategory.get_or_insert('root',name='Root',categories=categories)
	logging.info('created '+str(root))


def init_root_and_registry():
	global ROOT
	global REGISTRY
	ROOT = WidgetCategory.get_by_key_name('root')
	REGISTRY = []
	ROOT.expand('categories')
	for cat in ROOT.categories:
		cat.expand('widgets')
		for w in cat.widgets:
			w.add_config_props()
			REGISTRY.append(w)


def add_widget(key,dict):
	wc = WidgetCategory.get_or_insert(key,name=dict['name'])
	#logging.info('added widget category '+str(wc))
	widgets = []
	for w in dict['widgets']:
		wdef = WidgetRegistry.get_or_insert(w[0], name=w[1])
		#logging.info('added widget def '+str(wdef))
		widgets.append(wdef.key())
	wc.widgets = widgets
	wc.put()
	return wc


def get_widget_root():
	return ROOT, REGISTRY
